package org.training.gl.tdd.list;

import org.training.gl.tdd.util.ArrayUtils;

public class CustomArrayList<Obj> implements ICustomArrayList<Obj> {

	private Object[] array;

	private int size;

	public static final int INITIAL_CAPACITY = 5;

	public CustomArrayList() {
		array = new Object[INITIAL_CAPACITY];
		size = 0;
	}

	@Override
	public boolean contains(Obj o) {
		return indexOf(o) != -1;
	}

	private int indexOf(Obj o) {
		for (int i = 0; i < size; i++) {
			Obj item = get(i);
			if (item != null && item.equals(o)) {
				return i;
			}
			if (item == null && o == null) {
				return i;
			}
		}
		return -1;
	}

	@Override
	public int size() {
		return size;
	}

	private void grow() {
		Object[] newArray = new Object[array.length + INITIAL_CAPACITY];
		ArrayUtils.copy(array, newArray);
		array = newArray;
	}

	@Override
	public void add(Obj o) {
		if (size >= array.length) {
			grow();
		}

		array[size] = o;
		size = size + 1;
	}

	@Override
	public boolean remove(Obj o) {
		int index = indexOf(o);
		if (index == -1) {
			return false;
		}

		Object[] newArray = new Object[array.length - 1];
		ArrayUtils.copy(array, 0, index - 1, newArray, 0);
		ArrayUtils.copy(array, index + 1, array.length - 1, newArray, index);
		array = newArray;
		size = size - 1;
		return true;
	}

	@Override
	public void clear() {
		array = new Object[INITIAL_CAPACITY];
		size = 0;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Obj get(int index) {
		if (index < 0 || index >= size) {
			throw new IndexOutOfBoundsException(
					"Provided index is out of bounds");
		}
		return (Obj) array[index];
	}

}
